package com.geek.javase.ch18.videodemo.pattern.proxy.jdk;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.Arrays;

/**
 * 2025/4/5
 * * 需求1：新增日志
 *  * 需求2：统计耗时
 *  *
 *  * Spring的AOP、事务默认使用的是JDK动态代理，若没有使用接口就会使用CGLIB代理。
 *  *
 *  * 一.动态代理
 *  * 拦截对真实对象方法的直接访问，增强真实对象方法的功能
 *  *
 *  * 二.JDK动态代理：
 *  * 1.代理对象,不需要实现接口，但是目标对象要实现接口，否则不能用动态代理
 *  * 2.代理对象的生成，是利用JDK的API，动态的在内存中构建代理对象
 *  * 3.动态代理也叫做：JDK代理、接口代理
 *  *
 *  * 三.JDK动态代理的优缺点：
 *  * 优点：
 *  *      1.实现不变动目标方法的基础上，对原有方法实现了增强
 *  *      2.实现解耦，提高了软件系统的可扩展性
 *  * 缺点：
 *  *      只能针对接口的实现类做代理对象，普通类是不能做代理对象的。
 */
//代理对象 proxy
public class DynamicProxyBankLogService {
    //目标对象
    private IService target;
    //如果这里是直接使用BankService创建对象，是无法构建对象的
    /*private BankService target;*/

    public DynamicProxyBankLogService(IService target) {
        this.target = target;
    }

    public IService getProxy() {
        //代理对象
        IService proxy = null;

        //1.类加载器
        ClassLoader classLoader = target.getClass().getClassLoader();
        //2.实现接口
        Class<?>[] interfaces = target.getClass().getInterfaces();
        //3.执行处理器
        InvocationHandler handler = new InvocationHandler() {
            /**
             * 执行目标方法
             * @param proxy  代理对象（不用的）
             * @param method 目标对象中的方法对象
             * @param args   目标对象中的方法形参列表
             * @return 目标对象中的方法的返回值，若目标方法没有返回值则是null，若目标方法有返回值则是object
             * @throws Throwable
             */
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                //获得执行的目标方法的方法名称
                String name = method.getName();
                System.out.println("日志开始追踪:The Method "+name+"begin with"+ Arrays.toString(args));
                long l1  = System.currentTimeMillis();
                //执行目标方法
                Object invoke = method.invoke(target, args);
                long l2 = System.currentTimeMillis();
                System.out.println("日志追踪结束:The Method "+name+"end with"+ Arrays.toString(args)+"耗时"+(l2-l1)+"毫秒");
                return invoke;
            }
        };
        proxy = (IService) java.lang.reflect.Proxy.newProxyInstance(classLoader, interfaces, handler);
        return proxy;
    }
}
